#pragma once

#include <cstdint>
#include <memory>
#include <vector>
#include <iostream>

using dir_t = int8_t;
using cond_t = int16_t;
using case_t = uint32_t;
using event_t = uint64_t;
using closed_t = uint32_t;
using price_t = float;
using ftime_t = float;
using risk_t = float;

#ifndef ORIGIN_CONST
#define ORIGIN_CONST

const price_t phi = 0.6180339887498949; // 0.5 * (sqrt(5) - 1)
const price_t ppi = 0.3819660112501051; // 1 - phi

#ifndef THIS_IS_MY_SIGN_FUN
#define THIS_IS_MY_SIGN_FUN
template<typename T>
inline constexpr int8_t
sign(T val)
{
  return (T(0) < val) - (val < T(0));
}
#endif // THIS_IS_MY_SIGN_FUN

const int FOUR_HOURS_IN_MINS = (60 * 4);
const int THREE_HOURS_IN_MINS = (60 * 3);
const int TWO_HOURS_IN_MINS = (60 * 2);
const int AN_HOUR = 3600;
const int ONE_HALF_HOUR = 3600 + 1800;
const int TWO_HOURS = 7200;
const int MINUTES_10 = 10 * 60;
const int MINUTES_15 = 15 * 60;
const int MINUTES_45 = 45 * 60;
const int MINUTES_30 = 30 * 60;

const price_t HOP_FOR_COMMISION = 5;
const price_t BIG_PASS_LINE_DELTA = 25;

#endif // ORIGIN_CONST

enum EVENT_CHANGE_TYPE : event_t
{
  EVENT_CHANGE_NONE = 0,
  EVENT_5DIRS_CHANGED = 1,
  EVENT_TOM_REACHED = 2,
  EVENT_JERRY_REACHED = 4,
  EVENT_MICKEY_REACHED = 8,
  EVENT_ENERGY_DIR_CHANGED = 16,
  EVENT_SWING_CHANGED = 32,
  EVENT_SWING_DIR_CHANGED = 64,
  EVENT_REACHED_MARK_UP = 128,
  EVENT_BIG_DIR_CHANGED = 256,
  EVENT_PDC_DIR_CHANGED = 512,
  EVENT_FIGHT_DIR_CHANGED = 1024,
  EVENT_CE_DIR_CHANGED = 2048,
  EVENT_IMPORTANT_TURN = 4096,
  EVENT_BIG_NEEDLE_OCCURED = 8192,
  EVENT_TTS_CHANGED = 16384,
  EVENT_REACHED_MARK_DN = 32768,
  EVENT_TOM_REACHED_FORCED = 65536,
  EVENT_TURN_CHANGED = 131072,
  EVENT_SPACE_DIR_CHANGED = 262144,
  EVENT_SPACE_DIR_STABLE = 524288,
  EVENT_BIG_NEEDLE_DISAPPEARED = 1048576,
  EVENT_BIG_REVERSE_OCCURED = 2097152,
  EVENT_BIG_REVERSE_DISAPPEARED = 4194304,
  EVENT_EXPLICIT_DIR_CHANGED = 0x00800000,
  EVENT_FORCE_NEAR_DIR_CHANGED = 0x01000000,
  EVENT_FORCE_FAR_DIR_CHANGED = 0x02000000,
  EVENT_FORCE_NEAR_LEVEL_CHANGED = 0x04000000,
  EVENT_FORCE_FAR_LEVEL_CHANGED = 0x08000000,
  EVENT_SOLVED_NEAR_CHANGED = 0x10000000,
  EVENT_SOLVED_FAR_CHANGED = 0x20000000,
  EVENT_FORCE_RT_NEAR_DIR_CHANGED =   0x00040000000,
  EVENT_FORCE_RT_FAR_DIR_CHANGED =    0x00080000000,
  EVENT_FORCE_RT_NEAR_LEVEL_CHANGED = 0x00100000000,
  EVENT_FORCE_RT_FAR_LEVEL_CHANGED =  0x00200000000,
  EVENT_VISION_DIR_CHANGED =          0x00400000000,
  EVENT_INTENT_DIR_CHANGED =          0x00800000000,
  EVENT_VISION_WITH_SPACE =           0x01000000000,
  EVENT_TJM_DIR_CHANGED =             0x02000000000,
  EVENT_TOM_CLOSE_AND_STOPED =        0x04000000000,
  EVENT_TOM_REACHED_GOOD_WIN =        0x08000000000,
  EVENT_JERRY_REACHED_L2_FO =         0x01000000000,
  EVENT_FILTER_EVENT        =         0x02000000000,
};

template<class T>
class ShptrVector : public std::vector<std::shared_ptr<T>> {
public:
  ShptrVector() {}
  ShptrVector(const ShptrVector& pv)
    : std::vector<std::shared_ptr<T>>(pv) {
    for (size_t i = 0; i < pv.size(); ++i)
      std::vector<std::shared_ptr<T>>::emplace_back(pv[i]);
  }

  virtual ~ShptrVector() {
    for (size_t i = 0; i < std::vector<std::shared_ptr<T>>::size(); ++i)
      this->at(i)->reset();
    std::vector<std::shared_ptr<T>>::clear();
  }

  void set_deep(int deep) {
    deep_ = deep;
    std::vector<std::shared_ptr<T>>::resize(deep_ * 2);
    std::vector<std::shared_ptr<T>>::clear();
  }

  void vp_emplace_back(std::shared_ptr<T> t) {
    if (std::vector<std::shared_ptr<T>>::size() >= deep_ * 2) {
      std::move(std::vector<std::shared_ptr<T>>::begin() + deep_,
                std::vector<std::shared_ptr<T>>::end(),
                std::vector<std::shared_ptr<T>>::begin());
    }
    std::vector<std::shared_ptr<T>>::emplace_back(t);
  }

  void vp_push_back(std::shared_ptr<T> t) {
    if (std::vector<std::shared_ptr<T>>::size() >= deep_ * 2) {
      std::move(std::vector<std::shared_ptr<T>>::begin() + deep_,
                std::vector<std::shared_ptr<T>>::end(),
                std::vector<std::shared_ptr<T>>::begin());
    }
    std::vector<std::shared_ptr<T>>::emplace_back(t);
  }

  const ShptrVector& operator= (const ShptrVector& vp) {
    std::vector<std::shared_ptr<T>>::clear();

    for (auto&& iter = vp.begin(); iter != vp.end(); ++iter)
      std::vector<std::shared_ptr<T>>::emplace_back(*iter);

    return vp;
  }


  bool operator == (const ShptrVector& vp) {
    if (std::vector<std::shared_ptr<T>>::size() != vp.size())
      return false;
    for (size_t i = 0; i < std::vector<std::shared_ptr<T>>::size(); ++i)
      if ((*(std::vector<std::shared_ptr<T>>::at(i))) != (*(vp[i])))
        return false;
    return true;
  }

  bool operator != (const ShptrVector& vp) {
    if (std::vector<std::shared_ptr<T>>::size() != vp.size())
      return true;
    for (size_t i = 0; i < std::vector<std::shared_ptr<T>>::size(); ++i)
      if ((*(std::vector<std::shared_ptr<T>>::at(i))) != (*(vp[i])))
       return true;
    return false;
  }

  friend std::ostream& operator<< (std::ostream& out,
                                   const std::vector<std::shared_ptr<T>>& pv) {
    for (size_t i = 0; i < pv.size(); ++i) {
      if (i) out << "     ";
      out << (*(pv[i])) << '\n';
    }
    return out;
  }

private:
  uint32_t deep_ = 400;
};
